/**
 * =================================================
 * wxi.js
 *
 * A wangXi javascript daily dev toolkit
 *
 * keep it small and simple
 *
 * namespace, modular definition
 * async js, css loader, single and multiple mode
 * prototype based OOP
 * flexible widget
 *
 * @author sunny.w <iwisunny@gmail.com>
 *
 * =================================================
 */
var wxi = (function(g){
    var w = g.wxi || {};
    //basic prop/function from native js
    var toStr = Object.prototype.toString,
        hasOwn = Object.prototype.hasOwnProperty,
        slice = Array.prototype.slice,
        push = Array.prototype.push,
        indexOf = Array.prototype.indexOf,
        trim = String.prototype.trim,

        doc = g.document,
        loc = g.location,
        nav = g.navigator,

        isFunction = function(obj){
            return toStr.call(obj) === "[object Function]";
        },
        isArray = function(obj){
            return toStr.call(obj) === "[object Array]";
        },
        isObject = function(obj){
            return toStr.call(obj) === "[object Object]";
        };

    //child obj extends properties of parent obj
    var extend = function(child,parent){
        (child !== null) && isObject(child) && (function(){
            for(var prop in parent){
                if(hasOwn.call(parent, prop)){
                    child[prop] = parent[prop];
                }
            }
        })();
        return child;
    };

    /**
     * 采用Js原型链模拟传统的OOP
     *
     */
    var _class = function(parent, mixin){
        //temporary constructor to be returned
        var base = function(){
                //follow php __construct, assume js constructor named __construct
                this.__construct.apply(this, arguments);
            },

        //proxy constructor
            F = function(){};

        //override prototype chain
        base.fn = base.prototype;
        //add blank callback to __construct
        base.fn.__construct = function(){};

        if(parent && isFunction(parent) ){
            F.prototype = parent.prototype;
            base.fn = new F();
        }
        else if(parent && isObject(parent) ){
            extend(base.fn, parent);
        }

        if(mixin && isObject(mixin) ){
            extend(base.fn, mixin);
        }

        return base;
    };

    /**
     * 构造命名空间，便于分离设计，模块化开发
     *
     * @param ns
     * @param map
     * @param with_this
     * @returns {wxi|*|{}}
     */
    var namespace = function(ns, map){
        var parts = ns.split('.'),
            parent = g;

        //parts = parts[0] == 'wxi' ? parts.slice(1) : parts;

        for(var i= 0, len = parts.length; i<len; i++){
            if(parent[parts[i]] === undefined){
                parent[parts[i]] = {};
            }
            parent = parent[parts[i]];
        }

        if(isObject(map)){
            //add extra properties to current namespace
            extend(parent, map);
        }

        /*
        //bind to global
        parts.unshift('g');
        eval(parts.join('.')+' = parent');
        */

        return parent;
    };

    //fix IE problems
    if(!trim){
        String.prototype.trim = function(){
            return this.replace(/^(\s*)(.+)(\s*)/i, '$2');
        };
    }
    if(!indexOf){
        Array.prototype.indexOf = function(needle){
            for(var i= 0, len = this.length; i< len; i++){
                if(needle == this[i]){
                    return i;
                }
                else{
                    continue;
                }
            }
            return -1;
        };
    }

    var for_each = function(arr, fx){
        if(isObject(arr)){
            fx.call(null, arr);
        }
        else if(isArray(arr)){
            for(var i= 0, len = arr.length; i<len; i++){
                fx.call(null, arr[i], i);
            }
        }

    };

    var in_array = function(needle, stack){
        if(!isArray(stack)) return false;

        return stack.indexOf(needle) !== -1;
    };

    //require js config
    var require_conf = {
        jsBaseUrl: '/assets/js/',
        cssBaseUrl: '/assets/css/',
        path: []
    };

    var set_require_conf = function(option){
        extend(require_conf, option);
        return w;
    };

    //单个文件的异步加载
    var require = function(url, callback, option){
        var args = arguments;

        if(isArray(args[0])){
            //多文件同步加载模式
            use.apply(this, args);
        }
        else{
            //单文件异步加载模式
            var url_suffix = url.match(/\.(\w+)$/),
                type = url_suffix && url_suffix[1],
                accept_file = ['js', 'css'],
                s,
                fpath,
                path_prefix = '';

            if(!in_array(type, accept_file)){
                throw new Error('unknown file type, only accept js, css');
            }

            option = extend(require_conf, option);

            if(type == 'js'){
                s = doc.createElement('script');
                s.type = 'text/javascript';
                path_prefix = option.jsBaseUrl;
            }
            else if(type == 'css'){
                s = doc.createElement('link');
                s.rel = 'stylesheet';
                s.type = 'text/css';
                path_prefix = option.cssBaseUrl;
            }
            else{
                return false;
            }

            if(s.readyState){
                s.onreadystatechange = function(){
                    if(s.readyState == 'loaded' || s.readyState == 'complete'){
                        s.onreadystatechange = null;
                        isFunction(callback) && callback();
                    }
                }
            }
            else{
                s.onload = function(){
                    isFunction(callback) && callback();
                }
            }

            if( /^\.{1,2}\/.+$/.test(url) ){
                fpath = path_prefix + /^\.{1,2}\/(.+)$/.exec(url)[1];
            }
            else if( /^(https?:\/\/)/.test(url) || /^\//.test(url) ){
                fpath = url;
            }
            else{
                fpath = path_prefix + url;
            }

            if( !RegExp( '\\.' + type + '$').test(fpath) ){
                fpath += '.' + type;
            }

            if(type == 'js'){
                s.src = fpath;
            }
            else{
                s.href = fpath;
            }

            doc.getElementsByTagName('head')[0].appendChild(s);
        }

    };

    //多文件按依赖顺序加载，用异步回调触发下一次加载，模拟同步阻塞
    var use = function(file_arr, callback, option){
        var cur_file = file_arr.shift();
        if(file_arr.length > 0){
            //递归使用 require 异步加载
            require(cur_file, function(){
                use(file_arr,callback,option);
            },option);
        }
        else{
            require(cur_file, function(){
                isFunction(callback) && callback();
            }, option);
        }
    };

    extend(w, {
        setConfig: set_require_conf,
        require: require,
        namespace: namespace,
        Class: _class,
        extend: extend,
        map: for_each,
        isFunction: isFunction,
        isObject: isObject,
        isArray: isArray
    });

    return w;

})(this);


